package com.wms.logger;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;

import com.orhanobut.logger.FormatStrategy;
import com.orhanobut.logger.LogStrategy;

import java.text.SimpleDateFormat;
import java.util.Locale;

import static com.orhanobut.logger.Logger.ASSERT;
import static com.orhanobut.logger.Logger.DEBUG;
import static com.orhanobut.logger.Logger.ERROR;
import static com.orhanobut.logger.Logger.INFO;
import static com.orhanobut.logger.Logger.VERBOSE;
import static com.orhanobut.logger.Logger.WARN;

/**
 * CSV formatted file logging for Android.
 * Writes to CSV the following data:
 * epoch timestamp, ISO8601 timestamp (human-readable), log level, tag, log message.
 */
public class MyFormatStrategy implements FormatStrategy {

    private static final String NEW_LINE = System.getProperty("line.separator");
    private static final String SEPARATOR = " ";
    @NonNull
    private final SimpleDateFormat dateFormat;
    @NonNull
    private final LogStrategy logStrategy;
    @Nullable
    private final String tag;
    boolean showThreadInfo;

    private MyFormatStrategy(@NonNull Builder builder) {
        checkNotNull(builder);
        dateFormat = builder.dateFormat;
        logStrategy = builder.logStrategy;
        tag = builder.tag;
        showThreadInfo = builder.showThreadInfo;
    }

    @NonNull
    public static Builder newBuilder() {
        return new Builder();
    }

    @Override
    public void log(int priority, @Nullable String onceOnlyTag, @NonNull String message) {
        checkNotNull(message);

        String tag = formatTag(onceOnlyTag);

        StringBuilder builder = new StringBuilder();
        // human-readable date/timec
        builder.append(dateFormat.format(System.currentTimeMillis()));

        // level
        builder.append(SEPARATOR);
        builder.append(logLevel(priority));

        // tag
        builder.append("/");
        builder.append(tag);
        if (showThreadInfo) {
            builder.append("/");
            builder.append(Thread.currentThread().getName());
        }

        builder.append(":");
        builder.append(message);

        // new line
        builder.append(NEW_LINE);

        logStrategy.log(priority, tag, builder.toString());
    }

    @Nullable
    private String formatTag(@Nullable String tag) {
        if (!TextUtils.isEmpty(tag) && !tag.equalsIgnoreCase(this.tag)) {
            return this.tag + "-" + tag;
        }
        return this.tag;
    }

    public static final class Builder {
        SimpleDateFormat dateFormat;
        LogStrategy logStrategy;
        String tag = "PRETTY_LOGGER";
        String logPath;
        Context context;
        boolean showThreadInfo;
        @SuppressLint("SimpleDateFormat")
        SimpleDateFormat logFileFormat = new SimpleDateFormat("yyyy-MM-dd");
        int maxFileSize = 1024 * 1024;

        private Builder() {
        }

        @NonNull
        Builder maxFileSize(int val) {
            maxFileSize = val;
            return this;
        }

        @NonNull
        Builder logFileFormat(@Nullable SimpleDateFormat val) {
            logFileFormat = val;
            return this;
        }

        @NonNull
        Builder dateFormat(@Nullable SimpleDateFormat val) {
            dateFormat = val;
            return this;
        }

        @NonNull
        Builder logStrategy(@Nullable LogStrategy val) {
            logStrategy = val;
            return this;
        }

        @NonNull
        Builder tag(@Nullable String tag) {
            this.tag = tag;
            return this;
        }

        @NonNull
        Builder context(@Nullable Context context) {
            this.context = context;
            return this;
        }

        Builder logPath(String logPath) {
            this.logPath = logPath;
            return this;
        }

        Builder showThreadInfo(boolean showThreadInfo) {
            this.showThreadInfo = showThreadInfo;
            return this;
        }

        @NonNull
        MyFormatStrategy build() {
            if (dateFormat == null) {
                dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
            }
            if (logStrategy == null) {
                String folder = Logger.getLogPath(context, logPath);
                HandlerThread ht = new HandlerThread("AndroidFileLogger." + folder);
                ht.start();
                Handler handler = new DiskLogStrategy.WriteHandler(ht.getLooper(), folder, logFileFormat, maxFileSize);
                logStrategy = new DiskLogStrategy(handler);
            }
            return new MyFormatStrategy(this);
        }
    }

    static String logLevel(int value) {
        switch (value) {
            case VERBOSE:
                return "VERBOSE";
            case DEBUG:
                return "DEBUG";
            case INFO:
                return "INFO";
            case WARN:
                return "WARN";
            case ERROR:
                return "ERROR";
            case ASSERT:
                return "ASSERT";
            default:
                return "UNKNOWN";
        }
    }

    @NonNull
    static <T> T checkNotNull(@Nullable final T obj) {
        if (obj == null) {
            throw new NullPointerException();
        }
        return obj;
    }
}
